
/**
 * 执行滚动事件
 * @param callback 
 */
function emit(callback: (params: { scrollTop: number, scrollLeft: number }) => void) {
    const scrollTop = ScrollUtils.getScrollTop();
    const scrollLeft = ScrollUtils.getScrollLeft();
    callback({
        scrollTop,
        scrollLeft
    });
}

/**
 * 滚动到指定位置
 * @param start 开始位置
 * @param end  结束位置
 * @param cb 
 */
function scrollTo(start: number, end: number, time: number, cb?: () => void) {
    const distance = end - start;
    const interval = 10;
    time = time < interval ? interval : time;
    const step = Math.ceil(time / interval);
    const stepDistance = Math.floor(distance / step);
    let i = 0;
    const animate = () => {
        i++;
        start += stepDistance;
        if (i === step) {

            if (start !== end) {
                start = end;
            }
            window.scrollTo(0, start);
            if (cb) {
                cb();
            }
        } else {
            window.scrollTo(0, start);
            setTimeout(animate, interval);
        }
    }
    animate();

}

/**
 * 滚动到指定位置
 * @param start 开始位置
 * @param dom  节点
 * @param offset  偏移量
 * @param cb 
 */
function scrollToDom(start: number, dom: HTMLElement, offset: number, time: number, cb?: () => void) {
    const end = getOffsetTop(dom) - offset;
    const distance = end - start;
    const interval = 10;
    time = time < interval ? interval : time;
    const step = Math.ceil(time / interval);
    const stepDistance = Math.floor(distance / step);
    let i = 0;
    const animate = () => {
        i++;
        start += stepDistance;
        if (end != getOffsetTop(dom) - offset) {
            scrollToDom(start, dom, offset, time, cb);
            return;
        }
        if (i === step) {
            if (start !== end) {
                start = end;
            }
            window.scrollTo(0, start);
            if (cb) {
                cb();
            }
        } else {
            window.scrollTo(0, start);
            setTimeout(animate, interval);
        }
    }
    animate();

}

/**
 * 获取dom节点距离顶部距离
 * @param dom  
 */
function getOffsetTop(dom: HTMLElement) {
    let offsetTop = dom.offsetTop;
    while (dom.offsetParent) {
        dom = dom.offsetParent as HTMLElement;
        offsetTop += dom.offsetTop;
    }
    return offsetTop;
}

const ScrollUtils = {
    on(callback: (params: { scrollTop: number, scrollLeft: number }) => void) {
        const handler = () => {
            emit(callback);
        };
        window.addEventListener('scroll', handler, false);
        return {
            un() {
                window.removeEventListener('scroll', handler, false);
            }
        }
    },
    getScrollHeight() {
        const body = document.body || document.documentElement;
        return body.scrollHeight;
    },
    getScrollTop() {
        const body = document.body || document.documentElement;
        return body.scrollTop || window.pageYOffset || 0;
    },
    getScrollLeft() {
        const body = document.body || document.documentElement;
        return body.scrollLeft || window.pageXOffset || 0;
    },
    /**
     * 滚动到指定位置
     * @param scrollTop 
     * @param callback 
     */
    scrollToTo(scrollTop: number, time: number = 300): Promise<boolean> {
        return new Promise((res) => {
            const start = this.getScrollTop();
            scrollTo(start, scrollTop, time, () => res(true));
        });
    },
    /**
     * 滚动到指定节点
     * @param dom 
     * @param offset 
     */
    scrollToDom(dom: HTMLElement, offset: number = 0, time: number = 300): Promise<boolean> {
        return new Promise((res) => {
            const scrollTop = this.getScrollTop();
            scrollToDom(scrollTop, dom, offset, time, () => res(true));
        });

    }

}

export default ScrollUtils
